using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Timers;
using System.Text;

namespace Campus
{
    public class TextureMap
    {
        private Texture2D m_largeImage;
        private int m_rows;
        private int m_columns;
        private int m_width;
        private int m_height;
        public TextureMap(Texture2D image, int numRows, int numCols)
        {
            if (numRows < 1)
            {
                throw new ArgumentOutOfRangeException("numRows", "The number of rows should be at least 1");
            }
            if (numCols < 1)
            {
                throw new ArgumentOutOfRangeException("numCols", "The number of columns should be at least 1");
            }
            m_largeImage = image;
            m_rows = numRows;
            m_columns = numCols;
            m_width = image.Width / numCols;
            m_height = image.Height / numRows;
        }
        public int Rows
        {
            get { return m_rows; }
        }
        public int Cols
        {
            get { return m_columns; }
        }
        public int Height
        {
            get { return m_height; }
        }
        public int Width
        {
            get { return m_width; }
        }
        public Texture2D Image
        {
            get { return m_largeImage; }
        }
    }

    public class Animation
    {
        private List<Texture2D> m_imageList;
        private int m_updateTime;
        private int m_index;

        private bool m_isAnimating;

        private int m_currentTime;

        private int m_numberFrames;
        private Texture2D m_currentTexture;

        public bool WillLoop { get; private set; } 

        /// <summary>
        /// An animation class that makes putting in animated images easy. One only needs to use the
        /// CurrentTexture property in the game while the image the property references changes with
        /// a Timer within the Animation class.
        /// **If the list passed in as an argument is empty, the CurrentTexture property will always
        /// be null!**
        /// </summary>
        /// <param name="list">The list of Texture2D's to animate</param>
        /// <param name="time">The time, in milliseconds, between each image (framerate)</param>
        /// <param name="loop">Whether the animation should loop or not</param>
        public Animation(List<Texture2D> list, int time, bool loops)
        {
            m_updateTime = time;
            m_index = 0;
            WillLoop = loops;
            m_currentTime = 0;
            m_imageList = list;
            m_numberFrames = list.Count;
            m_currentTexture = m_imageList[m_index];
        }
        public void Start()
        {
            m_isAnimating = true;
        }
        public void Pause()
        {
            m_isAnimating = false;
        }
        public void ResetAnimation()
        {
            m_index = 0;
        }
        public void Update(GameTime gameTime)
        {
            if (!m_isAnimating)
            {
                return;
            }

            // Add the elapsed time to the time that has elapsed for the current frame
            m_currentTime += gameTime.ElapsedGameTime.Milliseconds;

            int numFramesToAdvance = m_currentTime / m_updateTime;

            // If enough time has elapsed to change the animation
            if (numFramesToAdvance > 0)
            {
                m_currentTime -= (numFramesToAdvance * m_updateTime);

                m_index += numFramesToAdvance;

                if (m_index + 1 >= m_numberFrames)
                {
                    if (!WillLoop)
                    {
                        m_index = m_numberFrames - 1;
                        Pause();
                    }
                    else
                    {
                        m_index = m_index % m_numberFrames;
                    }
                }
            }
        }
        public int FrameCount
        {
            get { return m_numberFrames; }
        }
        public Texture2D CurrentTexture
        {
            get { return m_imageList[m_index]; }
        }
        public bool IsAnimating
        {
            get { return m_isAnimating; }
        }
    }


    public class TextureMapAnimation
    {
        private TextureMap m_tMap;
        private Timer m_timer;
        private int m_index;
        private bool m_shouldLoop;
        private int m_numberFrames;
        private Vector2 m_position;

        public static List<TextureMapAnimation> gameList = new List<TextureMapAnimation>();

        public TextureMapAnimation(TextureMap map, Vector2 position, double time, bool loops)
        {
            m_timer = new Timer(time);
            m_index = 0;
            m_shouldLoop = loops;
            m_numberFrames = map.Cols * map.Rows;
            m_tMap = map;
            this.m_position = position;

            // Anonymous method that changes the current texture
            m_timer.Elapsed += new ElapsedEventHandler(delegate(object o, ElapsedEventArgs e)
            {
                if (++m_index >= m_numberFrames)
                {
                    if (m_shouldLoop)
                    {
                        m_index = 0;
                    }
                    else
                    {
                        m_index--;
                        m_timer.Stop();
                    }
                }                
            });
            gameList.Add(this);
        }
        public void Start()
        {
            m_timer.Start();
        }
        public void Pause()
        {
            m_timer.Stop();
        }
        public int FrameCount
        {
            get { return m_numberFrames; }
        }
        public bool IsAnimating
        {
            get { return m_timer.Enabled; }
        }
        public int Index
        {
            get { return m_index; }
        }
        public TextureMap Map
        {
            get { return m_tMap; }
        }
    }
}